{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy import spatial\n",
    "import matplotlib.pyplot as plt\n",
    "# 遗传算法\n",
    "from sko.GA import GA_TSP\n",
    "plt.rcParams['font.sans-serif']=['SimHei']\n",
    "plt.rcParams['axes.unicode_minus'] = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 城市的数量\n",
    "num_points = 50"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.76534842, 0.87081162],\n",
       "       [0.17752295, 0.66906436],\n",
       "       [0.78868937, 0.87074919],\n",
       "       [0.61921538, 0.05197232],\n",
       "       [0.91261604, 0.33423212],\n",
       "       [0.63177342, 0.20805046],\n",
       "       [0.59140788, 0.37212853],\n",
       "       [0.25900092, 0.93644716],\n",
       "       [0.10439758, 0.83294667],\n",
       "       [0.06789373, 0.3146207 ],\n",
       "       [0.57853316, 0.76813652],\n",
       "       [0.29225362, 0.79833205],\n",
       "       [0.45838867, 0.5683984 ],\n",
       "       [0.24804087, 0.50228318],\n",
       "       [0.78493034, 0.53523962],\n",
       "       [0.18353561, 0.45257212],\n",
       "       [0.61347509, 0.94319375],\n",
       "       [0.96573063, 0.55056585],\n",
       "       [0.80852619, 0.35368415],\n",
       "       [0.34083902, 0.63580773],\n",
       "       [0.36803329, 0.89551442],\n",
       "       [0.50649004, 0.18299813],\n",
       "       [0.20286451, 0.92758925],\n",
       "       [0.54494286, 0.56790044],\n",
       "       [0.32770678, 0.48778437],\n",
       "       [0.43969353, 0.64449382],\n",
       "       [0.19309608, 0.61070982],\n",
       "       [0.32010103, 0.20877592],\n",
       "       [0.39324383, 0.14507342],\n",
       "       [0.60595183, 0.75818182],\n",
       "       [0.36804229, 0.14099788],\n",
       "       [0.25965269, 0.08650257],\n",
       "       [0.21272413, 0.68312391],\n",
       "       [0.22700271, 0.7668398 ],\n",
       "       [0.480361  , 0.06084809],\n",
       "       [0.34673324, 0.07444557],\n",
       "       [0.61018326, 0.63947644],\n",
       "       [0.31202106, 0.58816007],\n",
       "       [0.78977571, 0.87484877],\n",
       "       [0.4137542 , 0.73257673],\n",
       "       [0.79235961, 0.49131897],\n",
       "       [0.7771137 , 0.0870604 ],\n",
       "       [0.32992534, 0.76348685],\n",
       "       [0.38866795, 0.37563519],\n",
       "       [0.54202341, 0.89250502],\n",
       "       [0.13515626, 0.46499853],\n",
       "       [0.91226605, 0.453903  ],\n",
       "       [0.20475566, 0.71014369],\n",
       "       [0.09620238, 0.13643334],\n",
       "       [0.74002153, 0.67521984]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 生成点坐标\n",
    "points_coordinate = np.random.rand(num_points, 2)\n",
    "points_coordinate#50个点 二维坐标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.         0.62148269 0.02334103 ... 0.58316244 0.9935129  0.19722473]\n",
      " [0.62148269 0.         0.64358462 ... 0.04928623 0.53880315 0.56253225]\n",
      " [0.02334103 0.64358462 0.         ... 0.60561762 1.00933542 0.20149512]\n",
      " ...\n",
      " [0.58316244 0.04928623 0.60561762 ... 0.         0.58388987 0.53640398]\n",
      " [0.9935129  0.53880315 1.00933542 ... 0.58388987 0.         0.83952009]\n",
      " [0.19722473 0.56253225 0.20149512 ... 0.53640398 0.83952009 0.        ]]\n",
      "(50, 50)\n"
     ]
    }
   ],
   "source": [
    "# 计算两点之间的距离\n",
    "distance_matrix = spatial.distance.cdist(points_coordinate, points_coordinate, metric='euclidean')\n",
    "print(distance_matrix)\n",
    "print(distance_matrix.shape)#这个是邻接矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 目标函数，输入路径 返回总距离\n",
    "# 使用方式：compute_distance(np.arange(num_points))\n",
    "def compute_distance(routine):\n",
    "    num_points, = routine.shape\n",
    "#     print(routine)\n",
    "#     print(routine.shape)\n",
    "    # 求和\n",
    "    return sum([distance_matrix[routine[i % num_points], routine[(i + 1) % num_points]] for i in range(num_points)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 遗传算法\n",
    "from sko.GA import GA_TSP\n",
    "# prob_mut 种群的新成员由变异而非交叉得来的概率\n",
    "ga_tsp = GA_TSP(func=compute_distance, n_dim=num_points, size_pop=50, max_iter=500, prob_mut=0.2)\n",
    "best_points, best_distance = ga_tsp.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 9 15 13 24 43 27 48 31 35 30 28 21 34  3 41  5  6 14 40 18  4 46 17 49\n",
      " 36 10 29  2 38  0 16 44 20 39 19 12 23 25 42 11  7 22  8 47 33  1 32 26\n",
      " 37 45] [6.27782602]\n"
     ]
    }
   ],
   "source": [
    "print(best_points,best_distance)#最优的点和距离"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 画图\n",
    "fig, ax = plt.subplots(1, 2)\n",
    "best_points_ = np.concatenate([best_points, [best_points[0]]])\n",
    "best_points_coordinate = points_coordinate[best_points_, :]\n",
    "ax[0].plot(best_points_coordinate[:, 0], best_points_coordinate[:, 1], 'o-r')\n",
    "ax[1].plot(ga_tsp.generation_best_Y)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
